package gria

import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.axis.message.MessageElement;
import org.apache.axis.message.addressing.EndpointReferenceType;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import uk.ac.soton.itinnovation.grid.types.MatchPattern;
import uk.ac.soton.itinnovation.grid.types.PolicyRule;
import uk.ac.soton.ecs.iam.grid.comms.client.RemoteDataService;
import uk.ac.soton.ecs.iam.grid.comms.client.DataConversation;
import uk.ac.soton.itinnovation.grid.types.ConversationID;

import auth.User;

import org.jsecurity.*;

class GriaFileController {
    
	
    def index = { 
    redirect(action:list,params:params)     
    }

    // the delete, save and update actions only accept POST requests
    def allowedMethods = [delete:'POST', save:'POST', update:'POST']

    def list = {
        if(!params.max) params.max = 10
                if (!params.max) params.max = 10
        if (!params.offset) params.offset = 0
        if (!params.sort) params.sort = "id"
        if (!params.order) params.order = "asc"

        def results = GriaFile.withCriteria {               
                or {
                   eq("owner", session.user)
                   readers{
                    eq("userName", session.user.userName)
                   }
                order(params.sort, params.order)
               } 
               
        }    
       [ griaFileList: results]
    }

    def show = {
        def griaFile = GriaFile.get( params.id )

        if(!griaFile) {
            flash.message = "GriaFile not found with id ${params.id}"
            redirect(action:list)
        }
        else { return [ griaFile : griaFile ] }
    }

    def delete = {
        def griaFile = GriaFile.get( params.id )
        if(griaFile) {
        
            EndpointReferenceType dataEPR = ConversationID.getEPR(griaFile.serviceAddress, griaFile.resourceID);
            DataConversation dc = session.user.helperProxyFactory.createProxy(dataEPR, DataConversation.class);     
            dc.destroy();
        
            griaFile.delete()
            flash.message = "GriaFile ${params.id} deleted"
            redirect(action:list)
        }
        else {
            flash.message = "GriaFile not found with id ${params.id}"
            redirect(action:list)
        }
    }

    def edit = {
        def griaFile = GriaFile.get( params.id )

        println "edit"
        if(!griaFile) {
            flash.message = "GriaFile not found with id ${params.id}"
            redirect(action:list)
        }
        else {
            return [ griaFile : griaFile ]
        }
    }

    def update = {
        def griaFile = GriaFile.get( params.id )
        if(griaFile) {
            User grantTo = User.findWhere(userName:params['grantTo'])
            print grantTo
            
            InputStream inStream = new FileInputStream(grailsApplication.config.gria.identity.issuerCertLocation);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
            inStream.close();

            
            EndpointReferenceType dataEPR = ConversationID.getEPR(griaFile.serviceAddress, griaFile.resourceID)
            DataConversation dc = session.user.helperProxyFactory.createProxy(dataEPR, DataConversation.class)     
     
            MatchPattern mp = new MatchPattern(grantTo.subjectDN,cert);
            PolicyRule pr = new PolicyRule(mp, "reader");
            try {
            dc.addPolicyRule(pr)
            griaFile.readers.add(grantTo)
            }
            catch (Exception e)
            {
            println "Operation not permitted by GRIA" 
            griaFile.errors.reject("gria.user.notPermitted")
            }
            if(!griaFile.hasErrors() && griaFile.save()) {
                render(view:'show',model:[griaFile:griaFile])
            }
            else {
                render(view:'edit',model:[griaFile:griaFile])
            }
        }
        else {
            flash.message = "GriaFile not found with id ${params.id}"
            redirect(action:edit,id:params.id)
        }
    }

    def create = {
        def griaFile = new GriaFile()
        griaFile.properties = params
        flash['from'] = flash['from']
        return ['griaFile':griaFile]
    }
  
    def save = {
   		 println "saveFile"
   		 def subject = SecurityUtils.getSubject();
         def owner = User.findByEmail(subject.principal)
         print owner
         print owner.subjectDN
   		 def f = request.getFile('file')
    	 if(!f.empty) {
    	 		File stagedFile = new File(grailsApplication.config.gria.identity.tempFileDir + f.getOriginalFilename());
     			f.transferTo(stagedFile);
     			if (owner.serviceFactory == null)
     			{
     			println "No Service Factory!!!"   			
     			}
     			if (session.user.serviceFactory == null)
                {
                println "No Session Service Factory!!!"             
                }
				RemoteDataService dataService = (RemoteDataService) session.user.serviceFactory.createServiceProxy(grailsApplication.config.gria.services.dataService);
				DataConversation dataconv = dataService.createStagingArea(params['description']);
				dataconv.saveFromFile(stagedFile);		
				    System.out.println("Add: " + dataconv.getEPR().getAddress());
                params['fileName'] =  f.getOriginalFilename();
				params['serviceAddress'] = dataconv.getEPR().getAddress().toString();
				params['resourceID'] = ((MessageElement)dataconv.getEPR().getParameters().get(0)).getChildNodes().item(0).toString();
				stagedFile.delete();
				
    		}    
  		 else {
     			flash.message = 'file cannot be empty'
       			redirect(action:'create')
   			 }
   		params['owner'] = owner;
   		params['created'] = new Date();
   		params['type'] = FileType.findWhere(type:params['type'])
   		
        def griaFile = new GriaFile(params)
        if(!griaFile.hasErrors() && griaFile.save()) {
            flash.message = "GriaFile ${griaFile.id} created"
            
             if ( flash['from'] == "fliteGeometry" )
                {
                    print "from flite geom"
                    redirect(controller:"fliteGeometry",action:"create",params:"[datFile:griaFile]")
                }
             else
                redirect(action:show,id:griaFile.id)
        }
        else {
            render(view:'create',model:[griaFile:griaFile])
        }
    }
    
    def copy = {
         println "copyStager"
         def griaFile = GriaFile.get(params.id)
         EndpointReferenceType dataEPR = ConversationID.getEPR(griaFile.serviceAddress, griaFile.resourceID)
         DataConversation existingData = session.user.helperProxyFactory.createProxy(dataEPR, DataConversation.class)     
         
         RemoteDataService dataService = (RemoteDataService) session.user.serviceFactory.createServiceProxy(grailsApplication.config.gria.services.dataService);
         DataConversation dataconv = dataService.createStagingArea(griaFile.description);
         dataconv.copyFrom(existingData);      
                              
         params['serviceAddress'] = dataconv.getEPR().getAddress().toString();
         params['resourceID'] = ((MessageElement)dataconv.getEPR().getParameters().get(0)).getChildNodes().item(0).toString();
         params['type'] = griaFile.type
         params['owner'] = session.user;
         params['created'] = new Date();
         //description now comes from params...
         //params['description'] = griaFile.description;
         params['fileName'] = griaFile.fileName;
        
         def newGriaFile = new GriaFile(params)
         if(!newGriaFile.hasErrors() && newGriaFile.save()) {
            flash.message = "GriaFile ${newGriaFile.id} created"
                if ( flash['from'] != null )
                {
                if ( flash['action'] != null )
                 redirect(controller:flash['from'],action:flash['action'])
                else
                 redirect(controller:flash['from'],action:'list')
                }
            else
                redirect(action:show,id:newGriaFile.id)
         }
         else {
            render(view:'create',model:[griaFile:newGriaFile])
        }
    }
    
    def download = {
     
      def griaFile = GriaFile.get( params.id )
      if(griaFile) {      
            EndpointReferenceType dataEPR = ConversationID.getEPR(griaFile.serviceAddress, griaFile.resourceID)
            DataConversation dc = session.user.helperProxyFactory.createProxy(dataEPR, DataConversation.class)     
            File stagedFile = new File(grailsApplication.config.gria.identity.tempFileDir + griaFile.fileName)
            dc.read(stagedFile)  
            response.setHeader("Content-Type", "application/octet-stream;")
            response.setHeader("Content-Disposition", "attachment; filename="+griaFile.fileName)
            response.setHeader("Content-Length", "${stagedFile.size()}")
            response.outputStream << stagedFile.readBytes() 
            stagedFile.delete();
      }
      else
      {
                flash.message = 'stager cannot be empty'
                redirect(action:show,id:params.id)
      }
    }
    

}
